/**
 *
 *  Copyright (c) 2011, AstroDAbis
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *      * Redistributions of source code must retain the above copyright notice,
 *        this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above copyright notice,
 *        this list of conditions and the following disclaimer in the documentation
 *        and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 *  OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
package org.jiscinvolve.astrodabis.mallow.control;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.context.request.WebRequest;

import org.jiscinvolve.astrodabis.mallow.model.api.Tag;
import org.jiscinvolve.astrodabis.mallow.model.api.Query;
import org.jiscinvolve.astrodabis.mallow.model.api.Result;
import org.jiscinvolve.astrodabis.mallow.model.api.Account;

import org.jiscinvolve.astrodabis.mallow.model.tap.TapTable;
import org.jiscinvolve.astrodabis.mallow.model.tap.TapObject;
import org.jiscinvolve.astrodabis.mallow.model.tap.TapService;

import org.jiscinvolve.astrodabis.mallow.model.jpa.ManagedObject;
import org.jiscinvolve.astrodabis.mallow.model.jpa.PersistentObject;

/**
 * A container for passing data between Spring controllers and JSP views.
 *
 */
public class ViewData
    {

    /**
     * Our debug logger.
     * 
     */
    private static Log log = LogFactory.getLog(ViewData.class);

    /**
     * The Spring redirect URI prefix.
     * 
     */
    public static final String REDIRECT_PREFIX = "redirect:" ;

    /**
     * The URL path for our Spring dispatcher servlet.
     * 
     */
    public static final String SERVLET_PATH = "/spring" ;

    /**
     * The URL path for the home page.
     * 
     */
    public static final String HOME_PATH = "/" ;

    /**
     * The URL path for the login page.
     * 
     */
    public static final String LOGIN_PATH = "/login" ;

    /**
     * The URL path for the logout page.
     * 
     */
    public static final String LOGOUT_PATH = "/logout" ;

    /**
     * The URL path for user Accounts.
     * 
     */
    public static final String USER_PATH = "/users" ;

    /**
     * The URL path for Tags.
     * 
     */
    public static final String TAG_PATH = "/tags" ;

    /**
     * The URL path for Queries.
     * 
     */
    public static final String QUERY_PATH = "/queries" ;

    /**
     * The URL path for Results.
     * 
     */
    public static final String RESULT_PATH = "/results" ;

    /**
     * The URL path for services.
     * 
     */
    public static final String SERVICE_PATH = "/services" ;

    /**
     * The URL path for tables.
     * 
     */
    public static final String TABLE_PATH = "/tables" ;

    /**
     * The URL path for objects.
     * 
     */
    public static final String OBJECT_PATH = "/objects" ;

    /**
     * The URL path for QRCodes.
     * 
     */
    public static final String QRCODE_PATH = "/qrcode" ;

    /**
     * Request attribute for a ViewData object.
     * 
     */
    public static final String VIEW_DATA = "data" ;

/*
org.springframework.web.util.UrlPathHelper
 *
public String getServletPath(HttpServletRequest request)
public String getContextPath(HttpServletRequest request)
public String getPathWithinApplication(HttpServletRequest request)
public String getPathWithinServletMapping(HttpServletRequest request)
 */

    /**
     * Public constructor.
     *
     */
    public ViewData(WebRequest request)
        {
        this.request = request ;
        }

    /**
     * Public constructor.
     *
     */
    public ViewData(WebRequest request, Account actor)
        {
        this(request);
        this.actor = actor ;
        }

    /**
     * Public constructor.
     *
     */
    public ViewData(WebRequest request, Account actor, Account user)
        {
        this(request, actor);
        this.user = user ;
        }

    /**
     * Public constructor.
     *
     */
    public ViewData(WebRequest request, Account actor, Tag tag)
        {
        this(request, actor);
        this.tag  = tag ;
        this.user = tag.owner() ;
        }

    /**
     * Public constructor.
     *
     */
    public ViewData(WebRequest request, Account actor, Query query)
        {
        this(request, actor);
        this.query = query ;
        this.user  = query.owner() ;
        }

    /**
     * Public constructor.
     *
     */
    public ViewData(WebRequest request, Account actor, Result result)
        {
        this(request, actor);
        this.result = result ;
        this.user   = result.owner() ;
        }

    /**
     * Public constructor.
     *
     */
    public ViewData(WebRequest request, Account actor, TapTable table)
        {
        this(request, actor);
        this.table = table ;
        this.user  = table.owner() ;
        }

    /**
     * Public constructor.
     *
     */
    public ViewData(WebRequest request, Account actor, TapObject object)
        {
        this(request, actor);
        this.object = object ;
        }

    /**
     * Public constructor.
     *
     */
    public ViewData(WebRequest request, Account actor, TapService service)
        {
        this(request, actor);
        this.service = service ;
        this.user    = service.owner() ;
        }

    /**
     * Our web request.
     *
     */
    private WebRequest request ;

    /**
     * The current actor.
     *
     */
    private Account actor ;

    /**
     * Get the current actor.
     *
     */
    public Account actor()
        {
        return this.actor ;
        }

    /**
     * Check if the current actor owns an object.
     *
     */
    public boolean owner(ManagedObject object)
        {
        return ((actor != null) && (actor.equals(object.owner())));
        }

    /**
     * The target user Account.
     *
     */
    private Account user ;

    /**
     * Get the target user Account.
     *
     */
    public Account user()
        {
        return this.user ;
        }

    /**
     * The target Tag.
     *
     */
    private Tag tag ;

    /**
     * Get the target Tag.
     *
     */
    public Tag tag()
        {
        return this.tag ;
        }

    /**
     * The target Query.
     *
     */
    private Query query ;

    /**
     * Get the target Query.
     *
     */
    public Query query()
        {
        return this.query ;
        }

    /**
     * The target Result.
     *
     */
    private Result result ;

    /**
     * Get the target Result.
     *
     */
    public Result result()
        {
        return this.result ;
        }

    /**
     * The target TapTable.
     *
     */
    private TapTable table ;

    /**
     * Get the target TapTable.
     *
     */
    public TapTable table()
        {
        return this.table ;
        }

    /**
     * The target TapObject.
     *
     */
    private TapObject object ;

    /**
     * Get the target TapObject.
     *
     */
    public TapObject object()
        {
        return this.object ;
        }

    /**
     * The target TapService.
     *
     */
    private TapService service ;

    /**
     * Get the target TapService.
     *
     */
    public TapService service()
        {
        return this.service ;
        }


    /**
     * Inner class for building URL paths.
     *
     */
    public class PathBuilder
        {

        /**
         * Public constructor.
         *
         */
        public PathBuilder(String path)
            {
            this.builder = new StringBuilder(
                path
                );
            this.append(
                SERVLET_PATH
                );
            }

        /**
         * Our StringBuilder.
         *
         */
        private StringBuilder builder ;

        /**
         * Append a Long identifier to our path.
         *
         */
        public void append(Long ident)
            {
            if (ident != null)
                {
                append(
                    ident.toString()
                    );
                }
            }

        /**
         * Append a suffix to our path.
         *
         */
        public void append(String suffix)
            {
            if ((suffix != null) && (suffix.length() > 0))
                {
                if (suffix.startsWith("/") == false)
                    {
                    builder.append(
                        "/"
                        );
                    }
                builder.append(
                    suffix
                    );
                }
            }

        @Override
        public String toString()
            {
            return builder.toString();
            }
        }
        
    /**
     * Create a StringBuilder initialised with our webapp context.
     *
     */
    public PathBuilder path()
        {
        return new PathBuilder(
            request.getContextPath()
            );
        }

    /**
     * Create a URL path.
     *
     */
    public PathBuilder path(String step)
        {
        PathBuilder path = path();
        path.append(
            step
            );
        return path;
        }

    /**
     * URL path for the home page.
     *
     */
    public PathBuilder home()
        {
        PathBuilder path = path();
        path.append(
            HOME_PATH
            );
        return path ;
        }

    /**
     * URL path for an Account.
     *
     */
    public PathBuilder path(Account user)
        {
        PathBuilder path = path();
        path.append(
            USER_PATH
            );
        path.append(
            user.name()
            );
        return path ;
        }

    /**
     * URL path for an Account.
     *
     */
    public PathBuilder path(Account user, String suffix)
        {
        PathBuilder path = path(
            user
            );
        path.append(
            suffix
            );
        return path;
        }

    /**
     * URL path for a Tag.
     *
     */
    public PathBuilder path(Tag tag)
        {
        PathBuilder path = path(
            tag.owner()
            );
        path.append(
            TAG_PATH
            );
        path.append(
            tag.name()
            );
        return path;
        }

    /**
     * URL path for a Tag.
     *
     */
    public PathBuilder path(Tag tag, String suffix)
        {
        PathBuilder path = path(
            tag
            );
        path.append(
            suffix
            );
        return path;
        }

    /**
     * URL path for a Query.
     *
     */
    public PathBuilder path(Query query)
        {
        PathBuilder path = path();
        path.append(
            QUERY_PATH
            );
        path.append(
            query.ident()
            );
        return path;
        }

    /**
     * URL path for a Query.
     *
     */
    public PathBuilder path(Query query, String suffix)
        {
        PathBuilder path = path(
            query
            );
        path.append(
            suffix
            );
        return path;
        }

    /**
     * URL path for a Result.
     *
     */
    public PathBuilder path(Result result)
        {
        PathBuilder path = path();
        path.append(
            RESULT_PATH
            );
        path.append(
            result.ident()
            );
        return path;
        }

    /**
     * URL path for a Result.
     *
     */
    public PathBuilder path(Result result, String suffix)
        {
        PathBuilder path = path(
            result
            );
        path.append(
            suffix
            );
        return path;
        }

    /**
     * URL path for a TapTable.
     *
     */
    public PathBuilder path(TapTable table)
        {
        PathBuilder path = path();
        path.append(
            TABLE_PATH
            );
        path.append(
            table.ident()
            );
        return path;
        }

    /**
     * URL path for a TapTable.
     *
     */
    public PathBuilder path(TapTable table, String suffix)
        {
        PathBuilder path = path(
            table
            );
        path.append(
            suffix
            );
        return path;
        }

    /**
     * URL path for a TapObject.
     *
     */
    public PathBuilder path(TapObject object)
        {
        PathBuilder path = path();
        path.append(
            OBJECT_PATH
            );
        path.append(
            object.ident()
            );
        return path;
        }

    /**
     * URL path for a TapObject.
     *
     */
    public PathBuilder path(TapObject object, String suffix)
        {
        PathBuilder path = path(
            object
            );
        path.append(
            suffix
            );
        return path;
        }

    /**
     * URL path for a TapService.
     *
     */
    public PathBuilder path(TapService service)
        {
        PathBuilder path = path();
        path.append(
            SERVICE_PATH
            );
        path.append(
            service.ident()
            );
        return path;
        }

    /**
     * URL path for a TapService.
     *
     */
    public PathBuilder path(TapService service, String suffix)
        {
        PathBuilder path = path(
            service
            );
        path.append(
            suffix
            );
        return path;
        }

    /**
     * URI to redirect to the home page.
     *
     */
    public String redirect()
        {
        PathBuilder path = new PathBuilder(
            REDIRECT_PREFIX
            );
        path.append(
            HOME_PATH
            );
        return path.toString();
        }

    /**
     * URI to redirect to an Account profile page.
     *
     */
    public String redirect(Account user)
        {
        PathBuilder path = new PathBuilder(
            REDIRECT_PREFIX
            );
        path.append(
            USER_PATH
            );
        path.append(
            user.name()
            );
        return path.toString();
        }

    /**
     * URI to redirect to a Query details page.
     *
     */
    public String redirect(Query query)
        {
        PathBuilder path = new PathBuilder(
            REDIRECT_PREFIX
            );
        path.append(
            QUERY_PATH
            );
        path.append(
            query.ident()
            );
        return path.toString();
        }

    /**
     * URI to redirect to a Tag details page.
     *
     */
    public String redirect(Tag tag)
        {
        PathBuilder path = new PathBuilder(
            REDIRECT_PREFIX
            );
        path.append(
            USER_PATH
            );
        path.append(
            tag.owner().name()
            );
        path.append(
            TAG_PATH
            );
        path.append(
            tag.name()
            );
        return path.toString();
        }

    /**
     * URI to redirect to a TapService page.
     *
     */
    public String redirect(TapService service)
        {
        PathBuilder path = new PathBuilder(
            REDIRECT_PREFIX
            );
        path.append(
            SERVICE_PATH
            );
        path.append(
            service.ident()
            );
        return path.toString();
        }

    /**
     * URI to redirect to a TapTable page.
     *
     */
    public String redirect(TapTable table)
        {
        PathBuilder path = new PathBuilder(
            REDIRECT_PREFIX
            );
        path.append(
            TABLE_PATH
            );
        path.append(
            table.ident()
            );
        return path.toString();
        }


    /**
     * URL path for a QRCode.
     *
     */
    public PathBuilder qrcode(PathBuilder path)
        {
        path.append(
            QRCODE_PATH
            );
        return path;
        }


    }

